package com.ruoyi.query.entity;

import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.ruoyi.common.annotation.DynamicAnnotation;
import com.ruoyi.util.ReflectUtil;
import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * **********************
 * * Author: XiaShiLong *
 * * Date  : 2021-03-27 *
 * * Time  : 13:01      *
 * * to    : lz&xm      *
 * **********************
 * 动态查询核心代码
 **/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class QueryTable {

    /**
     * 类名
     */
    private String className;

    /**
     * 表名
     */
    private String tableName;

    /**
     * 表名中文
     */
    private String tableNameCh;

    /**
     * 顶级类
     */
    private boolean superClass;

    /**
     * 别名
     */
    private String alias;


    /**
     * 查询列集合
     */
    private List<QueryColumn> columnList;

    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public static class QueryColumn {

        /**
         * 中文列名
         */
        private String columnNameCh;

        /**
         * 数据库列名
         */
        private String tableColumnName;

        /**
         * 数据类型
         */
        private String type;

        /**
         * 自定义类
         */
        private boolean isCustomizeClass;

        /**
         * 实体列名
         */
        private String columnClassName;

        /**
         * 关联表对象
         */
        private QueryTable table;

        /**
         * 别名
         */
        private String alias;

        /**
         * 关联条件 语句
         */
        private String associateSql;

        public static QueryColumn create(Field field, DynamicAnnotation annotation) {
            QueryColumn queryColumn = new QueryColumn();
            queryColumn.setCustomizeClass(annotation.isCustomizeClass());
            queryColumn.setAlias(annotation.alias());
            queryColumn.setColumnNameCh(annotation.value());
            queryColumn.setColumnClassName(field.getName());
            queryColumn.setTableColumnName(StringUtils.camelToUnderline(queryColumn.getColumnClassName()));
            queryColumn.setType(field.getType().getSimpleName());
            return queryColumn;
        }
    }

    /**
     * 创建查询对象
     *
     * @param clz     目标对象
     * @param isSuper 是否反射超类
     * @param before  递归时,前一个对象
     * @return QueryTable
     */
    public static QueryTable create(Class<?> clz, boolean isSuper, Class<?> before) {
        QueryTable queryTable = new QueryTable();
        queryTable.setSuperClass(isSuper);
        queryTable.setClassName(clz.getSimpleName());
        queryTable.setTableName(clz.getAnnotation(TableName.class).value());
        queryTable.setTableNameCh(clz.getAnnotation(ApiModel.class).value());
        Field[] fields = isSuper ? ReflectUtil.getFieldHaveSuperclass(clz) : clz.getDeclaredFields();
        List<QueryColumn> columns = new ArrayList<>();
        for (Field f : fields) {
            DynamicAnnotation annotation = f.getAnnotation(DynamicAnnotation.class);
            if (!f.getName().equals("serialVersionUID") && null != annotation) {
                QueryColumn queryColumn = QueryColumn.create(f, annotation);
                if (queryColumn.isCustomizeClass && !clz.equals(before)) {
                    queryColumn.setTable(create(f.getType(), false, clz));
                    queryColumn.setAssociateSql(queryTable.getTableName() + "." + annotation.associateColumn() + " = " + (!"".equals(annotation.alias()) ? annotation.alias() : queryColumn.getTable().getTableName()) + "." + annotation.mappingColumn());
                }
                columns.add(queryColumn);
            }
        }
        columns.forEach(
                c -> {
                    if (!"".equals(c.getAlias()) && null != c.getTable()) {
                        c.getTable().setAlias(c.getAlias());
                    }
                }
        );
        columns.removeIf(c -> !isSuper && (c.getAlias().equals("create_sys_user") || c.getAlias().equals("update_sys_user")));
        queryTable.setColumnList(columns);
        return queryTable;
    }

    public static String sql(QueryTable queryTable) {
        StringBuilder sb = new StringBuilder();
        SELECT(sb, queryTable);
        sb.deleteCharAt(sb.length() - 2);
        sb.append(" ").append("FROM ").append(queryTable.getTableName());
        JOIN(sb, queryTable);
        return sb.toString();
    }

    private static void SELECT(StringBuilder sb, QueryTable queryTable) {
        if (Objects.isNull(queryTable)) {
            return;
        }
        for (QueryColumn c : queryTable.getColumnList()) {
            if (!c.isCustomizeClass) {
                String n = null != queryTable.getAlias() && !"".equals(queryTable.getAlias()) ? queryTable.getAlias() : queryTable.getTableName();
                sb.append(n).append(".").append(c.getTableColumnName()).append(" AS ").append(n).append("_").append(c.getTableColumnName()).append(", ");
            } else {
                SELECT(sb, c.getTable());
            }
        }
    }

    private static void JOIN(StringBuilder sb, QueryTable queryTable) {
        queryTable.getColumnList().stream().filter(QueryColumn::isCustomizeClass).forEach(
                q ->
                {
                    sb.append(" LEFT JOIN ").append(q.getTable().getTableName());
                    if (null != q.getAlias() && !"".equals(q.getAlias())) {
                        sb.append(" AS ").append(q.getAlias());
                    }
                    sb.append(" ON ").append(q.getAssociateSql()).append(" ");
                }

        );
    }

}
